/* eslint-disable no-param-reassign */
/* eslint-disable prefer-destructuring */
/* eslint-disable no-mixed-operators */
/* eslint-disable no-restricted-globals */
/* eslint-disable no-plusplus */
/* eslint-disable object-curly-newline */
/* global window, Path2D */
import Base from 'widget-base';
import Model from './model';
import mainTpl from './templates/ui.tpl';
import Konva from 'konva';

export default Base.View.extend({
  initialize($el, data = {}) {
    this.model = new Model({
      widgetWidth: $el.width(),
      widgetHeight: $el.height(),
    });

    this.addClass('./resources/css/main.css');
    this.addClass('./resources/css/tooltik.css');
    this.$el.html(mainTpl(data));

    this.operations = [];
    this.num = 1;
    this.layer1 = {};
    this.isAddCircle = false;
    this.circles = [];
    this.tr = {};
    setTimeout(() => {
      this.inKonva();
    }, 500);
    window.widget = this;
    console.log(this);
  },

  events: {},

  __supportInteract: true,
  inKonva() {
    this.stage = new Konva.Stage({
      container: 'container',
      width: 900,
      height: 720,
    });
    this.layer1 = new Konva.Layer();
    this.tr = this.createTransformer();
    this.layer1.add(this.tr);
    this.stage.add(this.layer1);
    this.stage.on(
      'click',
      function (evt) {
        if (evt.target ===  this.stage || evt.target === this.layer1) {
          this.tr.nodes([]);
        }
        var pos =  this.stage.getPointerPosition();
        const x = Math.ceil(pos.x);
        const y = Math.ceil(pos.y);
        if (this.circles.length < 3) {
          let circle = this.createCricle(x, y);
          this.circles.push(circle)
          if (this.circles.length <= 2) {
            this.operations.push({
              type: 'addCircle',
              data: {
                x: x,
                y: y,
              },
            });
            this.layer1.add(circle);
          }
        }

        if (this.circles.length === 3 && !this.isAddCircle) {
          const points = [];
          this.circles.forEach((circle) => {
            points.push(circle.attrs.x, circle.attrs.y);
            circle.hide();
          });
          this.triangle = this.createLine(points);
          this.layer1.add(this.triangle);
           this.trianglePOints= this.triangle.attrs.points
           this.trianglePOints.push(this.triangle.attrs.points[0])
           this.trianglePOints.push(this.triangle.attrs.points[1])
          this.operations.push({
            type: 'createTriangle',
            data: {
              points: points,
              fill: '#00D2FF',
              stroke: 'black',
              strokeWidth: 1,
              closed: true,
            },
          });
          const A = [points[0], points[1]];
          const B = [points[2], points[3]];
          const C = [points[4], points[5]];
          const angle1Position = this.calculateOffsetPoint(A, B, C);
          const angle2Position = this.calculateOffsetPoint(B, A, C);
          const angle3Position = this.calculateOffsetPoint(C, A, B);
          const simpleText1 = this.createText(
            angle1Position[0],
            angle1Position[1],
            '1',
            'red'
          );
          const simpleText2 = this.createText(
            angle2Position[0],
            angle2Position[1],
            '2',
            'green'
          );
          const simpleText3 = this.createText(
            angle3Position[0],
            angle3Position[1],
            '3',
            'yellow'
          );
          const group = this.createGroup();
          group.position(this.triangle.position());
          group.add(this.triangle);
          group.add(simpleText1);
          group.add(simpleText2);
          group.add(simpleText3);
          this.layer1.add(group);
          this.layer1.draw();
          group.attrs.myPoint = points;
          this.FirstBox = group.getClientRect();
          group.on(
            'click tap',
            function (evt) {
              // 防止事件冒泡
              evt.cancelBubble = true;
              const clickedTriangle = evt.target;
              // 检查是否点击的是原始组，而不是克隆出来的
              if (clickedTriangle === this.triangle) {
                const clonedGroup = group.clone();
                clonedGroup.attrs.id = `clonedGroup${this.num}`;
                clonedGroup.position({
                  id: `clonedGroup${this.num}`,
                  x: group.x() + 22,
                  y: group.y() + 22,
                });
                clonedGroup.draggable(true);
                this.tr.nodes([clonedGroup]);   
                const width = this.tr.width();
                const height = this.tr.height();
                this.groupWidth = Math.round(width);
                this.groupHeight = Math.round(height);
                this.layer1.add(clonedGroup);
                clonedGroup.moveToTop();
                this.tr.moveToTop();
                this.operations.push({
                  type: 'clonedGroup',
                  data: {
                    id: `clonedGroup${this.num}`,
                    x: clonedGroup.x(),
                    y: clonedGroup.y(),
                    rotation: clonedGroup.rotation(),
                    points: this.triangle.points(),
                    fill: this.triangle.fill(),
                    stroke: this.triangle.stroke(),
                    strokeWidth: this.triangle.strokeWidth(),
                    closed: this.triangle.closed(),
                  },
                });
                this.num += 1;
                clonedGroup.on('dragmove', function (evt) {
                  const threshold = 15;
                  let distance = Infinity; // 初始化当前最小距离为无穷大
                  let srcPoint = null; // 初始化源点为空
                  let targetPoint = null; // 初始化目标点为空
                  var lineGuideStops =this.getLineGuideStops(evt.target);
                  var itemBounds = this.getObjectSnappingEdges(evt.target);
                  let index = 0
                  lineGuideStops.flat().forEach((v,i) => {
                    const {x,y} =v
                    itemBounds.forEach(p => {
                     const d2 = Math.sqrt(Math.pow(p.x - x, 2) + Math.pow(p.y - y, 2));
                     if (d2 <= threshold && d2 < distance) {
                       srcPoint = p;
                       targetPoint = v;
                       distance = d2;
                       index = i
                     }
                   })
                   }); 
                   if (srcPoint && targetPoint) {
                    evt.target.position({
                      x:evt.target.x() +targetPoint.x  -srcPoint.x,
                      y:evt.target.y()+ targetPoint.y -srcPoint.y
                    });
                  //  吸附完成之后
                  let  current = this.getObjectSnappingEdges(evt.target).filter(item=>item.x !==targetPoint.x  && item.y !== targetPoint.y);
                  let snaptriangle =[]
                  for (let index = 0; index < lineGuideStops.length; index++) {
                    const item = lineGuideStops[index];
                    for (let i = 0; i < item.length; i++) {
                      const p = item[i];
                      if(p.x ==targetPoint.x  &&  p.y == targetPoint.y) {
                       const res = item.filter(item=>item.x !==targetPoint.x  && item.y !== targetPoint.y)
                        snaptriangle.push(res)
                      }
                    }
                  }
                  let targetriangle=[]
                  if(snaptriangle.length ==1){
                    targetriangle.push(snaptriangle[0])
                  }else {
                    const X =[]
                    const Y = []
                    snaptriangle.forEach((item,index)=>{
                      item.forEach(p=>{
                        current.forEach(k=>{
                          X.push(k.x -p.x)
                          Y.push(k.y-p.y)
                        })
                      })
                    })
                 
                    const minX = X.reduce((minIdx, num, index, arr) => {
                      return num < arr[minIdx] ? index : minIdx;
                    }, 0);
                    const minY = Y.reduce((minIdx, num, index, arr) => {
                      return num < arr[minIdx] ? index : minIdx;
                    }, 0);
                    const index = Math.floor(minX)
                    targetriangle.push(snaptriangle[index])
                  }
                  targetriangle = targetriangle.flat()
                  console.log("目标",targetriangle,current);
                  let minDistance = 20
                  if( !targetriangle[0] ) return
                  current.forEach(p=>{
                    targetriangle.forEach(k=>{
                     const distance = this.pointToLineDistance(p,k,targetPoint)
                     if(distance < minDistance && distance >1) {
                      minDistance =distance
                      // console.log(distance,p,k);
                      const angle = this.calculateAngleA(targetPoint,p,k)
                      if(angle < 30) {
                        console.log("angle222",p,k,targetPoint,angle);
                        console.log(evt.target.rotation());
                        if(evt.target.rotation()>=0){
                         const x = Math.abs(p.x-k.x)
                         const y = Math.abs(p.y-k.y)
                         if(x<y) {
                          if(p.x > k.x) {
                            evt.target.rotation(evt.target.rotation()-angle)
                          }else {
                            evt.target.rotation(evt.target.rotation()+angle)
                          }
                         }else if (x>y){
                          if(p.y > k.y) {
                            evt.target.rotation(evt.target.rotation()+angle)
                          }else {
                            evt.target.rotation(evt.target.rotation()-angle)
                          }
                         }
                         
                        }else {
                          const x = Math.abs(p.x-k.x)
                          const y = Math.abs(p.y-k.y)
                          if(x<y) {
                            if(p.x > k.x) {
                              evt.target.rotation(evt.target.rotation()+angle)
                            }else {
                              evt.target.rotation(evt.target.rotation()-angle)
                            }
                           }else if (x>y){
                            if(p.y > k.y) {
                              evt.target.rotation(evt.target.rotation()-angle)
                            }else {
                              evt.target.rotation(evt.target.rotation()+angle)
                            }
                           }
                        }
                        return
                      }
                     
                     }
                    })
                  })

                  }
               

                }.bind(this));

                clonedGroup.on(
                  'dragend',
                  function (evt) {
                    this.stage.find('.guid-line').forEach(function (line) {
                      line.destroy();
                    });
                    this.operations.push({
                      type: 'dragend',
                      data: {
                        ...evt.target.attrs,
                      },
                    });
                  }.bind(this)
                );
                clonedGroup.on(
                  'transformend',
                  function (evt) {
                    this.operations.push({
                      type: 'transformend',
                      data: {
                        ...evt.target.attrs,
                      },
                    });
                  }.bind(this)
                );
                // 重新绘制图层
                this.layer1.draw();
              } else {
                this.tr.nodes([evt.target.parent]);
                evt.target.parent.moveToTop();
                this.tr.moveToTop();
              }
            }.bind(this)
          );
          this.isAddCircle = true;
        }
      }.bind(this)
    );
  },
  pointToLineDistance(A, B, C) {
    // 提取点的坐标
    const { x: x0, y: y0 } = A;
    const { x: x1, y: y1 } = B;
    const { x: x2, y: y2 } = C;

    // 计算直线方程 Ax + By + C = 0 的系数
    const A_coeff = y2 - y1;
    const B_coeff = x1 - x2;
    const C_coeff = x2 * y1 - x1 * y2;

    // 计算距离
    const distance = Math.abs(A_coeff * x0 + B_coeff * y0 + C_coeff) / Math.sqrt(A_coeff * A_coeff + B_coeff * B_coeff);

    return distance;
},
 calculateAngleA(A, B, C) {
  // 计算向量 AB 和 AC
  const AB = {x: B.x - A.x, y: B.y - A.y};
  const AC = {x: C.x - A.x, y: C.y - A.y};

  // 计算向量 AB 和 AC 的点积
  const dotProduct = AB.x * AC.x + AB.y * AC.y;

  // 计算向量 AB 和 AC 的模长
  const magnitudeAB = Math.sqrt(AB.x * AB.x + AB.y * AB.y);
  const magnitudeAC = Math.sqrt(AC.x * AC.x + AC.y * AC.y);

  // 计算余弦值
  const cosTheta = dotProduct / (magnitudeAB * magnitudeAC);

  // 计算角度（以度为单位）
  const angleA = Math.acos(cosTheta) * (180 / Math.PI);

  return angleA;
},
 /**
 * 获取直线引导线的停靠点。
 * 
 * 该方法用于计算舞台上除指定形状外的所有对象的引导线停靠点。
 * 它分别计算垂直和水平方向的停靠点，并返回一个包含这两个方向停靠点的对象。
 * 
 * @param {Object} skipShape - 需要被忽略不计算引导线停靠点的形状对象。
 * @returns {Object} - 包含垂直和水平方向停靠点数组的对象。
 */
getLineGuideStops(skipShape) {
  // 初始化垂直和水平方向的停靠点数组
  let arr = [];

  // 遍历舞台上所有类名为'object1'的元素，忽略skipShape
  this.stage.find('.object1').forEach(guideItem => {
    // 如果当前元素是需要忽略的形状，则跳过当前迭代
    if (guideItem === skipShape) {
      return;
    }
    // 获取当前元素的引导线点，并将其处理为与当前元素相关的三角形点
    const p = this.getTrianglePoints(this.trianglePOints, guideItem)
      arr.push(p)
  });

  // 返回包含垂直和水平方向停靠点数组的对象
  // return {
  //   vertical: vertical.flat(),
  //   horizontal: horizontal.flat()
  // };
  return arr
},

/**
 * 获取对象吸附边
 * @param {Object} node - 需要进行吸附计算的节点对象
 * @returns {Object} 包含垂直和水平方向的吸附边信息
 */
getObjectSnappingEdges(node) {
  // 计算节点与三角形各点的坐标
  const p = this.getTrianglePoints(this.trianglePOints, node)
  return p
  // return {
  //   // 垂直方向的吸附边信息
  //   vertical: [
  //     {
  //       guide: Math.round(p[0].x), // 吸附引导线的位置
  //       offset: Math.round(node.x() - p[0].x), // 节点到吸附引导线的偏移量
  //       snap: 'start' // 吸附类型为起始点
  //     },
  //     {
  //       guide: Math.round(p[1].x), // 吸附引导线的位置
  //       offset: Math.round(node.x() - p[1].x), // 节点到吸附引导线的偏移量
  //       snap: 'center' // 吸附类型为中心点
  //     },
  //     {
  //       guide: Math.round(p[2].x), // 吸附引导线的位置
  //       offset: Math.round(node.x() - p[2].x), // 节点到吸附引导线的偏移量
  //       snap: 'end' // 吸附类型为终点
  //     }
  //   ],
  //   // 水平方向的吸附边信息
  //   horizontal: [
  //     {
  //       guide: Math.round(p[0].y), // 吸附引导线的位置
  //       offset: Math.round(node.y() - p[0].y), // 节点到吸附引导线的偏移量
  //       snap: 'start' // 吸附类型为起始点
  //     },
  //     {
  //       guide: Math.round(p[1].y), // 吸附引导线的位置
  //       offset: Math.round(node.y() - p[1].y), // 节点到吸附引导线的偏移量
  //       snap: 'center' // 吸附类型为中心点
  //     },
  //     {
  //       guide: Math.round(p[2].y), // 吸附引导线的位置
  //       offset: Math.round(node.y() - p[2].y), // 节点到吸附引导线的偏移量
  //       snap: 'end' // 吸附类型为终点
  //     }
  //   ]
  // };
},
  /**
 * 根据给定的垂直和水平辅助线停靠点，以及项目边界，计算最接近的辅助线位置。
 * @param {Object} lineGuideStops - 包含垂直和水平辅助线停靠点的对象。
 * @param {Object} itemBounds - 包含项目边界的对象，有垂直和水平边界。
 * @returns {Array} - 返回一个包含最接近的辅助线信息的数组，包括位置、偏移量、方向和是否触发吸附。
 */
getGuides(lineGuideStops, itemBounds) {
  // 定义辅助线与项目边界之间的允许偏差值
  const GUIDELINE_OFFSET = 10;
  // 初始化垂直和水平方向的辅助线匹配结果数组
  var resultV = [];
  var resultH = [];

  // 遍历垂直方向的辅助线停靠点，寻找与项目边界最近的匹配点
  lineGuideStops.vertical.forEach(lineGuide => {
    itemBounds.vertical.forEach(itemBound => {
      // 计算辅助线与项目边界距离
      var diff = Math.abs(lineGuide - itemBound.guide);
      // 如果距离小于允许偏差，则认为辅助线与项目边界匹配
      if (diff < GUIDELINE_OFFSET) {
        resultV.push({
          lineGuide: lineGuide,
          diff: diff,
          snap: itemBound.snap,
          offset: itemBound.offset
        });
      }
    });
  });

  // 遍历水平方向的辅助线停靠点，寻找与项目边界最近的匹配点
  lineGuideStops.horizontal.forEach(lineGuide => {
    itemBounds.horizontal.forEach(itemBound => {
      // 计算辅助线与项目边界距离
      var diff = Math.abs(lineGuide - itemBound.guide);
      // 如果距离小于允许偏差，则认为辅助线与项目边界匹配
      if (diff < GUIDELINE_OFFSET) {
        resultH.push({
          lineGuide: lineGuide,
          diff: diff,
          snap: itemBound.snap,
          offset: itemBound.offset
        });
      }
    });
  });

  // 初始化最终的辅助线数组，用于存储最接近的垂直和水平辅助线信息
  var guides = [];
  // 寻找垂直方向上距离最近的辅助线
  var minV = resultV.sort((a, b) => a.diff - b.diff)[0];
  // 寻找水平方向上距离最近的辅助线
  var minH = resultH.sort((a, b) => a.diff - b.diff)[0];

  // 如果存在垂直方向上的最近辅助线，则添加到最终结果数组中
  if (minV) {
    guides.push({
      lineGuide: minV.lineGuide,
      offset: minV.offset,
      orientation: 'V',
      snap: minV.snap
    });
  }
  // 如果存在水平方向上的最近辅助线，则添加到最终结果数组中
  if (minH) {
    guides.push({
      lineGuide: minH.lineGuide,
      offset: minH.offset,
      orientation: 'H',
      snap: minH.snap
    });
  }

  // 返回最终的辅助线数组
  return guides;
},
/**
 * 计算三角形顶点在经过一组变换后的坐标，包括旋转和平移。
 * 
 * @param {Array} triangle - 表示三角形顶点坐标的数组，每个顶点是一对[x, y]坐标。
 * @param {Object} group - 表示变换组的对象，包括旋转角度和平移距离。
 * @returns {Array} - 返回表示变换后坐标的对象数组。
 */
getTrianglePoints(triangle, group) {
  var points = triangle;
  var transformedPoints = [];
  var angle = group.rotation() * Math.PI / 180;

  for (var i = 0; i < points.length - 2; i += 2) {
      var x = points[i];
      var y = points[i + 1];

      // 应用旋转变换
      var rotatedX = x * Math.cos(angle) - y * Math.sin(angle);
      var rotatedY = x * Math.sin(angle) + y * Math.cos(angle);

      // 应用平移变换
      transformedPoints.push({
          x: rotatedX + group.x(),
          y: rotatedY + group.y()
      });
  }

  return transformedPoints;
},
 
  // 重置
  reset() {
    this.layer1.destroyChildren();
    this.layer1.draw();
    this.operations = [];
    this.num = 1;
    this.isAddCircle = false;
    this.circles = [];
    this.tr = this.createTransformer();
    this.layer1.add(this.tr);
  },
 
  stepBack() {
    const lastOperation = this.operations.pop();
    if (lastOperation) {
      switch (lastOperation.type) {
        case 'addCircle':
          this.circles.pop().destroy();
          break;
        case 'createTriangle':
          this.layer1.findOne('#group').destroy();
          this.circles.pop();
          this.circles.forEach((circle) => circle.show());
          this.isAddCircle = false;
          break;
        case 'clonedGroup':
          this.layer1
            .findOne((node) => {
              return (
                node.getClassName() === 'Group' &&
                node.x() === lastOperation.data.x &&
                node.y() === lastOperation.data.y
              );
            })
            .destroy();
          break;
        case 'dragend':
          this.revertToPreviousState(lastOperation);
          break;
        case 'transformend':
          this.revertToPreviousState(lastOperation);
          break;
        default:
          break;
      }
      this.layer1.draw();
    }
  },
  revertToPreviousState(lastOperation) {
    // Find the previous state of the element in the operations stack
    const previousState = this.operations
      .slice()
      .reverse()
      .find((op) => op.data.id === lastOperation.data.id);
    if (previousState) {
      const element = this.layer1.findOne(`#${previousState.data.id}`);
      if (element) {
        element.position({
          x: previousState.data.x,
          y: previousState.data.y,
        });
        element.rotation(previousState.data.rotation);
        element.scaleX(previousState.data.scaleX);
        element.scaleY(previousState.data.scaleY);
      }
    }
  },
  calculateAngle(A, B, C) {
    const AB = [B[0] - A[0], B[1] - A[1]];
    const AC = [C[0] - A[0], C[1] - A[1]];
    const dotProduct = AB[0] * AC[0] + AB[1] * AC[1];
    const magnitudeAB = Math.sqrt(AB[0] ** 2 + AB[1] ** 2);
    const magnitudeAC = Math.sqrt(AC[0] ** 2 + AC[1] ** 2);
    const cosTheta = dotProduct / (magnitudeAB * magnitudeAC);
    const angle = Math.acos(cosTheta) * (180 / Math.PI);
    return angle.toFixed(2);
  },
  calculateOffsetPoint(P1, P2, P3) {
    const midPoint = [(P2[0] + P3[0]) / 2, (P2[1] + P3[1]) / 2];
    return [
      P1[0] + ((midPoint[0] - P1[0]) * 1) / 4,
      P1[1] + ((midPoint[1] - P1[1]) * 1) / 4 - 10,
    ];
  },
  createCricle(clientX, clientY) {
    return new Konva.Circle({
      x: clientX,
      y: clientY,
      radius: 10,
      fill: 'red',
      visible: true,
    });
  },
  createLine(points) {
    return new Konva.Line({
      points: points,
      fill: '#00D2FF',
      stroke: 'black',
      strokeWidth: 1,
      closed: true,
    });
  },
  createText(x, y, text, color) {
    return new Konva.Text({
      x: x,
      y: y,
      text: text,
      fontSize: 30,
      fontFamily: 'Calibri',
      fill: color,
      align: 'left',
      verticalAlign: 'top',
    });
  },
  createGroup() {
    return new Konva.Group({
      id: 'group',
      name:'object1'
    });
  },
  createTransformer() {
    return new Konva.Transformer({
      rotateEnabled: true,
      resizeEnabled: false,
      rotateAnchorOffset: 30, // 旋转控制柄与图形的距离
      anchorSize: 40, // 旋转控制柄的大小
      borderStrokeWidth: 2, // 边框粗细
      rotationSnaps: [-180,-0,0,180],
    });
  },
  submit() {
    if (this.operations.length > 0) {
      const data = JSON.parse(JSON.stringify(this.operations));
      this.sendInteractData &&
        this.sendInteractData({
          action: 'submitResult',
          data: {
            operations: data,
            widgetId: this.itemId,
            widgetType: 'triangularPlanarMosaic',
          },
          time: Date.now(),
        });
    }
  },
  refreshUI(options) {
  
  },
});
